/**
 * 安装应用
 */
import { DependencyContainer, useTransaction, toSuccess, watchAddon, ROOT, HttpError } from '@sker/core'
import { SysAddon, SysAddonMenu } from '@sker/entities';
import { useReqBody } from '@sker/runtime';
import { join } from 'path';
import { z } from 'zod';
import { exec } from 'child_process'
import { exists, readFile, readFileSync } from 'fs-extra';

const initExec = async (command: string, options: any = {}) => {
    return new Promise<void>((resolve, reject) => {
        const root = process.cwd();
        const npmInstall = exec(command, { cwd: root, ...options })
        npmInstall.on('close', () => resolve())
        npmInstall.on('error', (e) => reject(e))
        npmInstall.stdout.pipe(process.stdout)
    })
}

export default async (container: DependencyContainer) => {
    const root = container.resolve(ROOT)
    const input = z.object({
        name: z.string()
    })
    const body = input.parse(useReqBody())
    await useTransaction(async m => {
        // 检查是否安装 报错或者没找到记录均为未安装
        const installSql = join(root, 'addons', body.name, 'install.sql')
        const installExisit = await exists(installSql)
        if (installExisit) {
            const sql = readFileSync(installSql).toString('utf-8')
            await m.query(sql)
        }
        const initSql = join(root, 'addons', body.name, 'init.sql')
        const initSqlExisit = await exists(initSql)
        if (initSqlExisit) {
            const sql = readFileSync(initSql).toString('utf-8')
            await m.query(sql)
        }
    }).catch(e => { })
    const res = await useTransaction(async m => {
        const { name } = body;
        const addonRoot = join(root, 'addons', name)
        const pkgRoot = join(addonRoot, 'package.json')
        const pkgString = await readFile(pkgRoot, { encoding: 'utf-8' })
        const pkg = JSON.parse(pkgString)
        const item = await m.findOne(SysAddon, { where: { name: body.name } })
        const [scope, addon] = name.split('/')
        const sysAddon = m.create(SysAddon, {
            name: pkg.name,
            version: pkg.version,
            title: pkg.title,
            desc: pkg.description,
            scope: scope.replace('@', ''),
            parent: pkg.parent,
            code: pkg.code
        })
        if (item) {
            sysAddon.id = item.id;
        };
        await m.save(SysAddon, sysAddon)
        // menu
        const menus: { title: string, url: string }[] = pkg.menus || [];
        const exMenus = await m.find(SysAddonMenu, { where: { addon: pkg.name } })
        const rmMenus = exMenus.filter(it => {
            return !menus.find(m => m.url === it.url)
        }).map(it => it.id)
        const addonMenus = menus.map(menu => {
            const item = exMenus.find(it => {
                return it.addon === pkg.name && it.url === menu.url
            })
            const entity = m.create(SysAddonMenu, {
                title: menu.title,
                url: menu.url,
                addon: pkg.name
            })
            if (item) {
                entity.id = item.id;
            }
            return entity;
        })
        addonMenus.length > 0 && await m.save(SysAddonMenu, addonMenus)
        rmMenus.length > 0 && await m.delete(SysAddonMenu, rmMenus)
        // 编译core模块
        await initExec('pnpm run tsc', { cwd: addonRoot })
        // 打包模块前端文件
        await watchAddon(scope.replace('@', ''), addon, false)
        return { name, addonRoot, pkgRoot, pkg }
    })
    return toSuccess(res)
}
